package com.atom.module.lib.opengles.geometry

class Line3 {

    val origin: Vec3 = Vec3()

    val direction: Vec3 = Vec3()

    constructor()

    constructor(origin: Vec3, direction: Vec3) {
        this.origin.set(origin)
        this.direction.set(direction)
    }

    constructor(line: Line3) {
        origin.set(line.origin)
        direction.set(line.direction)
    }

    fun set(origin: Vec3, direction: Vec3): Line3 {
        this.origin.set(origin)
        this.direction.set(direction)
        return this
    }

    /**
     * Computes a Cartesian point a specified distance along this line.
     * 该线✖️一个系数 的新的点
     * @throws IllegalArgumentException If the specified result argument is null or undefined.
     */
    fun pointAt(distance: Double): Vec3 {
        return Vec3(
            origin.x + direction.x * distance,
            origin.y + direction.y * distance,
            origin.z + direction.z * distance
        )
    }

    /**
     * 将此行设置为指定的段。 这条线的起点在第一个端点，方向从第一个端点延伸到第二个端点。
     */
    fun setToSegment(pointA: Vec3, pointB: Vec3): Line3 {
        this.origin.set(pointA)
        this.direction.set(pointB.x - pointA.x, pointB.y - pointA.y, pointB.z - pointA.z)
        return this
    }


    fun triStripIntersection(
        points: FloatArray,
        stride: Int,
        elements: ShortArray,
        count: Int,
        result: Vec3
    ): Boolean {
        if (points.size < stride) {
            throw IllegalArgumentException(
                "Line triStripIntersections missingBuffer"
            )
        }
        if (stride < 3) {
            throw IllegalArgumentException(
                "Line triStripIntersections invalidStride"
            )
        }
        if (elements.isEmpty()) {
            throw IllegalArgumentException(
                "Line triStripIntersections missingBuffer"
            )
        }
        if (count < 0) {
            throw java.lang.IllegalArgumentException(
                "Line triStripIntersection invalidCount"
            )
        }

        val directionX = direction.x
        val directionY = direction.y
        val directionZ = direction.z

        val originX = origin.x
        val originY = origin.y
        val originZ = origin.z

        var tMin = Double.POSITIVE_INFINITY
        val EPSILON = 0.00001
        // 获取三角形的第一个定点
        // Get the triangle strip's first vertex.
        var vertex = elements[0] * stride
        var vert1x = points[vertex++].toDouble()
        var vert1y = points[vertex++].toDouble()
        var vert1z = points[vertex].toDouble()
        // 获取三角形的第2个定点
        // Get the triangle strip's second vertex.
        vertex = elements[1] * stride
        var vert2x = points[vertex++].toDouble()
        var vert2y = points[vertex++].toDouble()
        var vert2z = points[vertex].toDouble()
        // 计算每个三角形与指定射线的交点。
        var idx = 2
        while (idx < count) {

            val vert0x = vert1x
            val vert0y = vert1y
            val vert0z = vert1z
            vert1x = vert2x
            vert1y = vert2y
            vert1z = vert2z
            // Get the triangle strip's next vertex.
            vertex = elements[idx] * stride
            vert2x = points[vertex++].toDouble()
            vert2y = points[vertex++].toDouble()
            vert2z = points[vertex].toDouble()
            // find vectors for two edges sharing point a: vert1 - vert0 and vert2 - vert0
            val v0_to_v1_line_x = vert1x - vert0x
            val v0_to_v1_line_y = vert1y - vert0y
            val v0_to_v1_line_z = vert1z - vert0z
            // 获取
            val v0_to_v2_line_x = vert2x - vert0x
            val v0_to_v2_line_y = vert2y - vert0y
            val v0_to_v2_line_z = vert2z - vert0z
            // Compute cross product of line direction and edge2
            /**
             *    0    0>1   1
             *
             *    0>2
             *
             *    2
             */
            // 获取该线段方向和 线段2的叉积 法线
            // direction [-1,0,1] v0>v2[0,1,0]
            val direction_0To2_normal_x =
                directionY * v0_to_v2_line_z - directionZ * v0_to_v2_line_y // =-1
            val direction_0To2_normal_y =
                directionZ * v0_to_v2_line_x - directionX * v0_to_v2_line_z  //= 0
            val direction_0To2_normal_z =
                directionX * v0_to_v2_line_y - directionY * v0_to_v2_line_x  // -1

            // [-1 , 0 , -1]
            // 创建一个 叉积
            /**
             *  0 > Z
             */
            // Get determinant
            // 判断该法线和选段0>1的点积累
            val det =
                v0_to_v1_line_x * direction_0To2_normal_x + v0_to_v1_line_y * direction_0To2_normal_y + v0_to_v1_line_z * direction_0To2_normal_z // edge1 dot p
            // 计算 该法线和 线段0>1 的点积 det 约等于 0
            if (det > -EPSILON && det < EPSILON) { // if det is near zero then ray lies in plane of triangle
                idx++ // 点积 == 0 说明该线和该面 共面 // 平行
                continue
            }
            // 不垂直
            val inv_det = 1.0 / det
            // Compute distance for vertex A to ray origin: origin - vert0
            // 获取 点0 > 原点的 一个向量
            val v0_to_origin_line_x = originX - vert0x
            val v0_to_origin_line_y = originY - vert0y
            val v0_to_origin_line_z = originZ - vert0z
            // Calculate u parameter and test bounds: 1/det * t dot p
            //  u == 1 说明线段的起点在 面表面
            val u =
                inv_det * (v0_to_origin_line_x * direction_0To2_normal_x + v0_to_origin_line_y * direction_0To2_normal_y + v0_to_origin_line_z * direction_0To2_normal_z)
            if (u < -EPSILON || u > 1 + EPSILON) {
                idx++ // 说明该线的起点 在 v0 -> v1 这条线上
                continue
            }
            // Prepare to test v parameter: tvec cross edge1
            // 获取 点0指向线段原点的向量和 0->1 的法向量
            val v0ToOrigin_v0ToV1_normal_x =
                v0_to_origin_line_y * v0_to_v1_line_z - v0_to_origin_line_z * v0_to_v1_line_y
            val v0ToOrigin_v0ToV1_normal_y =
                v0_to_origin_line_z * v0_to_v1_line_x - v0_to_origin_line_x * v0_to_v1_line_z
            val v0ToOrigin_v0ToV1_normal_z =
                v0_to_origin_line_x * v0_to_v1_line_y - v0_to_origin_line_y * v0_to_v1_line_x
            // Calculate v parameter and test bounds: 1/det * dir dot q
            val v =
                inv_det * (directionX * v0ToOrigin_v0ToV1_normal_x + directionY * v0ToOrigin_v0ToV1_normal_y + directionZ * v0ToOrigin_v0ToV1_normal_z)
            if (v < -EPSILON || u + v > 1 + EPSILON) {
                idx++
                continue
            }
            // Calculate the point of intersection on the line: t = 1/det * edge2 dot q
            val t =
                inv_det * (v0_to_v2_line_x * v0ToOrigin_v0ToV1_normal_x + v0_to_v2_line_y * v0ToOrigin_v0ToV1_normal_y + v0_to_v2_line_z * v0ToOrigin_v0ToV1_normal_z)
            if (t >= 0 && t < tMin) {
                tMin = t
            }
            idx++
        }
        if (tMin != Double.POSITIVE_INFINITY) {
            result.set(
                originX + directionX * tMin,
                originY + directionY * tMin,
                originZ + directionZ * tMin
            )
        }
        return tMin != Double.POSITIVE_INFINITY
    }

    override fun equals(other: Any?): Boolean {
        if (this === other) return true
        if (other == null || javaClass != other.javaClass) return false
        val line: Line3 = other as Line3
        return if (origin != line.origin) false else direction == line.direction
    }

    override fun hashCode(): Int {
        var result = origin.hashCode()
        result = 31 * result + direction.hashCode()
        return result
    }

    override fun toString(): String {
        return "Line3 [origin=$origin, direction=$direction]"
    }
}